#pragma once

// hpp文件，即源文件和头文件的结合,在这里面声明，同时在这里面定义
#include<iostream>
#include<unistd.h>
#include<pthread.h>
#include<functional>
#include<string>
#include<cassert>
#include <memory>

//C式的 , C式就不需要适配函数start，直接传入就行
//typedef void*(*fun_t)(void*);
class Threads;

// 这种面向对象式的，因为类型不匹配所以要适配函数
typedef std::function<void*(void*)> fun_t;



class Context
{
public:
    Context()
    :_Thd(nullptr)
    ,_arvg(nullptr)
    {}

public:
   Threads* _Thd;
   void* _arvg;
};

class Threads
{
public:
   // 我思，线程的id是要pthread_create之后才有的，所以不用传入
   Threads(const std::string& name,int number = 1,fun_t fun = nullptr,void* arvg = nullptr)
    :_fun(fun)
    ,_arvg(arvg)
    ,_id(0)
    {
        _name = name;
        _name+= std::to_string(number);

        Context *ctx = new Context();
        ctx->_Thd = this;
        ctx->_arvg = arvg;

        // 线程在创建完这个后就自动取执行了
        int n = pthread_create(&_id, nullptr,start,ctx);
        //int n = pthread_create(&_id, nullptr,fun,_arvg);
    
        
        assert(n == 0);
        //在realse版本中，防止assert被优化掉导致n没有被用上带了的警告
        (void)n;
    }
   
   // 一个this指针够了, fun是外界传过来的所以，内部能做到的就只是调用fun而不是直接定义fun
   // 利用start作为跳板去执行外面传入的要执行的函数
   static void* start(void *argv)
   {
        Context *ctx = static_cast<Context*>(argv);
        //void* ret = ctx->_Thd->_fun(ctx->_arvg);
        void* ret = ctx->_Thd->run(ctx->_arvg);
    
        
        delete ctx;
        return ret;
   }

   void join()
   {
       int ret = pthread_join(_id,nullptr);
       assert(ret == 0);
       (void)ret;
   }

   void* run(void* argv)
   {
        return _fun(argv);
   }

private:
    std::string _name;
    pthread_t _id;
    fun_t _fun;
    void * _arvg; 
};



